;;;
;;; display.c for Kernel in /home/icecrime/Kernel
;;;
;;; Made by U-ICE\icecrime
;;; Login   <icecrime@epita.fr>
;;;

[bits 16]
[org 0x7c00]

jmp boot			; Jump the entry point

;;; Our data section
;;; We declare our GDT here.

GDTR:
GDTSIZE	DW	GDT_END - GDT - 1
GDTBASE	DD	0x500
GDT:
NULL_SEL	EQU $-GDT 	; Mandatory null selector
	DD	0x0
	DD	0x0
CODESEL		EQU $-GDT	; Flat code selector [r-x]
	DW	0xFFFF
	DW	0x0
	DB	0x0
	DB	0x9A
	DB	0xCF
	DB	0x0
DATASEL		EQU $-GDT	; Flat data selector [rw-]
	DW	0xFFFF
	DW	0x0
	DB	0x0
	DB	0x92
	DB	0xCF
	DB	0x0
GDT_END:

drive	DB	0
msg0	DB	13, 10, 13, 10, "JAK Bootloader", 13, 10, 0
msg1	DB	"   - Setting up A20", 13, 10, 0
msg2	DB	"   - Loading kernel", 13, 10, 0
msg3	DB	"   - Setting up GDT", 13, 10, 0
msg4	DB	"   - Entering protected mode", 13, 10, 0


;;; Putch
putch:
	push	bx
	mov	ah,0x0e
	mov	bh, 0x00
	mov	bl, 0x47
	int	0x10
	pop	bx
	ret

;;; Puts
puts:
	push	si
	jmp	.puts_loop
.puts_aff:
	call	putch
.puts_loop:
	lodsb
	or	al, al
	jnz	.puts_aff
	pop	si
	ret

;;; Entry point
boot:
	mov	si, msg0
	call	puts
	;;; We use the same value [actually 0x7c00] for
	;;; every segment register. Our sections our not
	;;; rellocated in any way, so all our offsets
	;;; are relative to our bootloader address.
	mov	[drive], dl	; Remember boot drive number
	mov	ax, cs
	mov	ds, ax
	mov	es, ax
	mov	fs, ax
	;;; Set up a tiny stack for our bootloader.
	;;; Stack address :		0x1000
	;;; Stack size in bytes :	512 [0x200]
	mov	ax, 0x1D0
	mov	ss, ax
	mov	sp, 0x200
	;;; Setup video segment
	mov	ax, 0xb800
	mov	gs, ax
	;;; Jump to the initialization.
	jmp	init

;;; Init
init:
	;;; This part should enable the A20 gate. But I'm
	;;; lazy, and I know that most modern BIOSes (and
	;;; Bochs included) boot the A20 enabled.
	mov	si, msg1
	call	puts

;;; Read the kernel from the floppy
read:
	mov	si, msg2
	call	puts
.read_loop:
	xor	ax, ax
	mov	dl, [drive]
	int	0x13
	jc	.read_loop
	mov	ax, 0xffff
	mov	es, ax
	mov	bx, 0x10
	mov	ah, 2
	mov	al, 17
	mov	ch, 0
	mov	cl, 2
	mov	dh, 0
	int	0x13
	jc	.read_loop
	mov	ax, 0xffff
	mov	es, ax
	mov	bx, 0x2210
	mov	ah, 2
	mov	al, 18
	mov	ch, 0
	mov	cl, 1
	mov	dh, 1
	int	0x13
	mov	dx,0x3f2
	mov	al,0x0c
	out	dx,al

;;; Install our basic GDT (protected flat).
;;; We first copy it to GDTBASE [0x500]
gdt_install:
	mov	si, msg3
	call	puts
	xor	ax, ax
	mov	ds, ax
	mov	es, ax
	mov	si, GDT		; Source address
	mov	di, [GDTBASE]	; Destination address
	mov	cx, [GDTSIZE]	; Loop counter
	cld			; Direction flag
	rep	movsb		; while (cx--) *(di++) == *(si++);

;;; Switch to protected mode
pmode_install:
	mov	si, msg4
	call	puts
	cli
	mov	eax, cr0
	or	al, 1
	mov	cr0, eax
	;;; Load GdT
	lgdt	[GDTR]
	;;; cs = CODESEL
	jmp	CODESEL:flush


[bits 32]

flush:
	;;; Dummy loop, usefull to have time and read
	;;; our debug messages.
	mov	ecx, 0xffffff
.sleep_loop:
	loop	.sleep_loop
	;;; Data are now isolated from code through the
	;;; two segments defined in our GDT.
	;;; Make the access to data, stack, etc relative
	;;; to this data segment selector.
	mov	eax, DATASEL
	mov	ds, eax
	mov	es, eax
	mov	fs, eax
	mov	gs, eax
	mov	ss, eax
	mov	esp, 0xffff
	;;; We sleep for some time, in order to appreciate our
	;;; lovely debugging messages.
	;;; Code is relative to CODESEL (the first descriptor,
	;;; null excepted, of our GDT).
	;;; This will jump into our src/kentry.asm.
	jmp	CODESEL:0x100000
	hlt

;;; Bootloader signature
TIMES 510-($-$$) DB 0
	DW 0xAA55
